package com.qezhhnjy.bilibili;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhaoyangfu - 2021/4/6 21:52
 */
@Slf4j
public class LockSupportDemo {

    public static void main(String[] args) {
        // wait notify需要在synchronized同步块/方法中才能生效，否则报异常
        // objectLock();
        // condition需要再lock.lock()后才生效，否则报异常
        // 且这两种方式中的如果notify/signal先触发，wait/await则无法被唤醒
        // conditionLock();

        lockSupportLock();
    }

    public static void objectLock() {
        Object lock = new Object();

        new Thread(() -> {
            synchronized (lock) {
                log.info("开始sync...");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
                log.info("sync被唤醒...");
            }
        }).start();

        new Thread(() -> {
            synchronized (lock) {
                log.info("通知sync...");
                lock.notify();
            }
        }).start();
    }

    public static void conditionLock() {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {
            lock.lock();
            try {
                log.info("condition come in ...");
                condition.await();
                log.info("condition 被唤醒...");
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();
                log.info("condition 通知...");
            } finally {
                lock.unlock();
            }
        }).start();
    }

    public static void lockSupportLock() {
        Thread a = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("{} come in...", Thread.currentThread().getName());
            LockSupport.park();
            log.info("{} 被唤醒...", Thread.currentThread().getName());
        });
        a.start();
        LockSupport.park(a);

        new Thread(() -> {
            LockSupport.unpark(a);
            log.info("{} 通知了 {}", Thread.currentThread().getName(), a.getName());
        }).start();
    }
}
